/******************************************************************************* * Signavio Core Components * Copyright (C) 2012 Signavio GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package de.hpi.bpmn2_0.factory; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONArray; import org.json.JSONObject; import org.oryxeditor.server.diagram.generic.GenericShape; import de.hpi.bpmn2_0.model.FormalExpression; import de.hpi.bpmn2_0.model.activity.Activity; import de.hpi.bpmn2_0.model.activity.loop.ComplexBehaviorDefinition; import de.hpi.bpmn2_0.model.activity.loop.LoopCharacteristics; import de.hpi.bpmn2_0.model.activity.loop.MultiInstanceFlowCondition; import de.hpi.bpmn2_0.model.activity.loop.MultiInstanceLoopCharacteristics; import de.hpi.bpmn2_0.model.activity.loop.StandardLoopCharacteristics; import de.hpi.bpmn2_0.model.data_object.DataState; import de.hpi.bpmn2_0.model.event.EventDefinition; import de.hpi.bpmn2_0.model.event.ImplicitThrowEvent; import de.hpi.bpmn2_0.model.misc.IoOption; import de.hpi.bpmn2_0.model.misc.ItemKind; import de.hpi.bpmn2_0.model.misc.Property; /** * Common factory for BPMN 2.0 activities * * @author Sven Wagner-Boysen * */ public abstract class AbstractActivityFactory extends AbstractShapeFactory { /** * Sets common attributes of activity (task, subprocess, event-subprocess) * derived from the source shape. * * @param activity * The resulting activity. * @param shape * The source diagram shape. */ protected void setStandardAttributes(Activity activity, GenericShape shape) { this.setCommonAttributes(activity, shape); /* Handle isCompensation Property */ this.setCompensationProperty(activity, shape); /* Loop Characteristics */ this.createLoopCharacteristics(activity, shape); /* Properties */ activity.getProperty().addAll(this.createPropertiesList(shape)); /* Start and Completion Quantity */ this.setStartAndCompletionQuantity(activity, shape); /* Collect data for IOSpecification */ this.collectIoSpecificationInfo(activity, shape); } /** * Takes the complex property input set as well as output set and stores * them in a hash map for further processing. * @param shape * @param activity */ private void collectIoSpecificationInfo(Activity activity, GenericShape shape) { activity.getOutputSetInfo().add(this.collectSetInfoFor(shape, "dataoutputset")); activity.getInputSetInfo().add(this.collectSetInfoFor(shape, "datainputset")); } /** * Generic method to parse data input and output set properties. * * @param property * Identifies the shape's property to handle either a output or input set. */ private HashMap<String, IoOption> collectSetInfoFor(GenericShape shape, String property) { String ioSpecString = shape.getProperty(property); HashMap<String, IoOption> options = new HashMap<String, IoOption>(); if(ioSpecString != null && !(ioSpecString.length() == 0)) { try { JSONObject ioSpecObject = new JSONObject(ioSpecString); JSONArray ioSpecItems = ioSpecObject.getJSONArray("items"); /* Retrieve io spec option definitions */ for (int i = 0; i < ioSpecItems.length(); i++) { JSONObject propertyItem = ioSpecItems.getJSONObject(i); IoOption ioOpt = new IoOption(); /* Name */ String name = propertyItem.getString("name"); if(name == null || name.length() == 0) continue; /* Optional */ String isOptional = propertyItem.getString("optional"); if(isOptional != null && isOptional.equalsIgnoreCase("true")) ioOpt.setOptional(true); /* While executing */ String whileExecuting = propertyItem.getString("whileexecuting"); if(whileExecuting != null && whileExecuting.equalsIgnoreCase("true")) ioOpt.setOptional(true); options.put(name, ioOpt); } } catch(Exception e) { e.printStackTrace(); } } return options; } /** * Process the compensation property. * * @param activity * @param shape */ private void setCompensationProperty(Activity activity, GenericShape shape) { activity .setIsForCompensation((shape.getProperty("isforcompensation") != null ? shape .getProperty("isforcompensation").equalsIgnoreCase( "true") : false)); } /** * Sets the start quantity of the activity based on the data of the shape. * * @param activity * @param shape * The resource shape */ private void setStartAndCompletionQuantity(Activity activity, GenericShape shape) { /* Start quantity */ String startQuantity = shape.getProperty("startquantity"); if(startQuantity != null) { try { activity.setStartQuantity(BigInteger.valueOf(Integer.valueOf(startQuantity))); } catch(Exception e) { e.printStackTrace(); /* Set to default value in case of an exception */ activity.setStartQuantity(BigInteger.valueOf(1)); } } /* Completion quantity */ String completionQuantity = shape.getProperty("completionquantity"); if(completionQuantity != null) { try { activity.setCompletionQuantity(BigInteger.valueOf(Integer.valueOf(completionQuantity))); } catch(Exception e) { /* Set to default value in case of an exception */ e.printStackTrace(); activity.setCompletionQuantity(BigInteger.valueOf(1)); } } } /** * Entry method to create the {@link LoopCharacteristics} for a given * activity's shape. * * @param activity * @param shape * @return */ protected void createLoopCharacteristics(Activity activity, GenericShape shape) { /* Distinguish between standard and multiple instance loop types */ String loopType = shape.getProperty("looptype"); if (loopType != null && !(loopType.length() == 0)) { /* Loop type standard */ if (loopType.equalsIgnoreCase("Standard")) activity.setLoopCharacteristics(createStandardLoopCharacteristics(shape)); /* Loop type multiple instances */ else if (loopType.equalsIgnoreCase("Parallel") || loopType.equalsIgnoreCase("Sequential")) { activity.setLoopCharacteristics(createMultiInstanceLoopCharacteristics(shape, loopType)); } } } /** * * * @param shape * @return */ protected List<Property> createPropertiesList(GenericShape shape) { ArrayList<Property> propertiesList = new ArrayList<Property>(); String propertiesString = shape.getProperty("properties"); if(propertiesString != null && !(propertiesString.length() == 0)) { try { JSONObject propertyObject = new JSONObject(propertiesString); JSONArray propertyItems = propertyObject.getJSONArray("items"); /* * Retrieve property definitions and process * them. */ for (int i = 0; i < propertyItems.length(); i++) { JSONObject propertyItem = propertyItems.getJSONObject(i); Property property = new Property(); /* Name */ String name = propertyItem.getString("name"); if(name != null && !(name.length() == 0)) property.setName(name); /* Data State */ String dataState = propertyItem.getString("datastate"); if(dataState != null && !(dataState.length() == 0)) property.setDataState(new DataState(dataState)); /* ItemKind */ String itemKind = propertyItem.getString("itemkind"); if(itemKind != null && !(itemKind.length() == 0)) property.setItemKind(ItemKind.fromValue(itemKind)); /* Structure */ String structureString = propertyItem.getString("structure"); if(structureString != null && !(structureString.length() == 0)) property.setStructure(structureString); /* isCollection */ String isCollection = propertyItem.getString("iscollection"); if(isCollection != null && isCollection.equalsIgnoreCase("false")) property.setCollection(false); else property.setCollection(true); propertiesList.add(property); } } catch(Exception e) { e.printStackTrace(); } } return propertiesList; } /** * Creates the loop characteristics for multiple instances loops. * * @param shape * @param loopType */ private MultiInstanceLoopCharacteristics createMultiInstanceLoopCharacteristics(GenericShape shape, String loopType) { MultiInstanceLoopCharacteristics miLoop = new MultiInstanceLoopCharacteristics(); /* Determine whether it is parallel or sequential */ if (loopType.equalsIgnoreCase("Parallel")) miLoop.setIsSequential(false); else miLoop.setIsSequential(true); /* Set loop cardinality */ String loopCardinalityString = shape .getProperty("loopcardinality"); if (loopCardinalityString != null && !(loopCardinalityString.length() == 0)) { FormalExpression loopCardinality = new FormalExpression( loopCardinalityString); miLoop.setLoopCardinality(loopCardinality); } /* Reference required DataInput */ // miLoop.setLoopDataInput(value) // Task t = null; // t.get /* Completion condition */ String completionCondition = shape .getProperty("completioncondition"); if (completionCondition != null && !(completionCondition.length() == 0)) { FormalExpression completionConditionExpr = new FormalExpression( completionCondition); miLoop.setCompletionCondition(completionConditionExpr); } /* Handle loop behavior */ handleLoopBehaviorAttributes(shape, miLoop); return miLoop; } /** * Processes the attributes that are related to the loop behavior. * * @param shape * @param miLoop */ private void handleLoopBehaviorAttributes(GenericShape shape, MultiInstanceLoopCharacteristics miLoop) { String behavior = shape.getProperty("behavior"); if (behavior != null && !(behavior.length() == 0)) { miLoop.setBehavior(MultiInstanceFlowCondition .fromValue(behavior)); } /* Complex behavior */ if (miLoop.getBehavior().equals( MultiInstanceFlowCondition.COMPLEX)) { try { String comBehavDefString = shape .getProperty("complexbehaviordefinition"); JSONObject complexDef = new JSONObject( comBehavDefString); JSONArray complexDefItems = complexDef .getJSONArray("items"); /* * Retrieve complex behavior definitions and process * them. */ for (int i = 0; i < complexDefItems.length(); i++) { JSONObject complexDefItem = complexDefItems .getJSONObject(i); ComplexBehaviorDefinition comBehavDef = new ComplexBehaviorDefinition(); /* Condition */ String condition = complexDefItem .getString("cexpression"); if (condition != null && !(condition.length() == 0)) comBehavDef.setCondition(new FormalExpression( condition)); /* Event */ ImplicitThrowEvent event = new ImplicitThrowEvent( complexDefItem.getString("ceventdefinition")); comBehavDef.setEvent(event); miLoop.getComplexBehaviorDefinition().add( comBehavDef); } } catch (Exception e) { e.printStackTrace(); } /* Handle none behavior choice */ } else if (miLoop.getBehavior().equals( MultiInstanceFlowCondition.NONE)) { String noneBehavString = shape .getProperty("nonebehavioreventref"); if (noneBehavString != null && !(noneBehavString.length() == 0)) { miLoop.setNoneBehaviorEventRef(EventDefinition .createEventDefinition(noneBehavString)); } /* Handle one behavior choice */ } else if (miLoop.getBehavior().equals( MultiInstanceFlowCondition.ONE)) { String oneBehavString = shape .getProperty("onebehavioreventref"); if (oneBehavString != null && !(oneBehavString.length() == 0)) { miLoop.setOneBehaviorEventRef(EventDefinition .createEventDefinition(oneBehavString)); } } } /** * Creates a {@link StandardLoopCharacteristics} object based on the shape's * properties. * * @param shape * The resource shape * @return * The {@link StandardLoopCharacteristics} */ private LoopCharacteristics createStandardLoopCharacteristics(GenericShape shape) { StandardLoopCharacteristics standardLoop = new StandardLoopCharacteristics(); /* Set loop condition */ String loopConditionString = shape.getProperty("loopcondition"); if (loopConditionString != null && !(loopConditionString.length() == 0)) { FormalExpression loopCondition = new FormalExpression( loopConditionString); standardLoop.setLoopCondition(loopCondition); } /* Determine the point in time to check the loop condition */ String testBeforeString = shape.getProperty("testbefore"); if (testBeforeString != null && testBeforeString.equalsIgnoreCase("true")) { standardLoop.setTestBefore(true); } else { standardLoop.setTestBefore(false); } /* Set the maximum number of loop iterations */ try { standardLoop.setLoopMaximum(BigInteger.valueOf(Integer .parseInt(shape.getProperty("loopmaximum")))); } catch (Exception e) { /* In case of an exception do not set a loop iteration cap */ } return standardLoop; } }